<?php

/**
* alltosun.com 银联支付接口 index.php
* ============================================================================
* 版权所有 (C) 2009-2014 北京互动阳光科技有限公司，并保留所有权利。
* 网站地址: http://www.alltosun.com
* ----------------------------------------------------------------------------
* 许可声明: 这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
* ============================================================================
* $Author: 吴松键 (wusj@alltosun.com) $
* $Date: 2014-9-25 下午2:10:43 $
* $Id$
*/

class Action
{
    private $quick_config;

    public function __construct()
    {
        exit('当前支付不能使用');
        require_once MODULE_PATH.'/openapi/config/quickpay_config.php';
        $this->quick_config = quickpay_config::$pay_params;
    }

    /**
     * 付款
     */
    public function pay()
    {
        $order_id = Request::getParam('order_id', '');

        if (!$order_id) {
            return array('支付超时，请重新发起支付', 'error', AnUrl('order'));
        }

        $order_info = _uri('order', $order_id);
        if ($order_info['id'] < 1) {
            return array('支付超时，请重新发起支付', 'error', AnUrl('order'));
        }
        if ($order_info['progress'] >= 5) {
            return array('支付超时，请重新发起支付', 'error', AnUrl('order'));
        }

        $order_args = array(
            'transType'     => quickpay_config::CONSUME,                    // 支付
            //'orderAmount'   => $order_info['price']*100,    // 订单总价
            'orderAmount'   => 1,
            'orderNumber'   => order_helper::order_id_encode($order_id),    // 订单编号
            'orderTime'     => date('YmdHis'),                              // 当前时间
            'customerIp'    => get_ip(),                              // 用户ip
            'frontEndUrl'   => AnUrl('openapi/quickpay/pay_return'),  // 前台回调URL
            'backEndUrl'    => AnUrl('openapi/quickpay/pay_notify'),  // 后台回调URL
            'orderCurrency' => quickpay_config::CURRENCY_CNY,       // 交易币种
        );

        $param_string = $this->build_request_param_string($order_args);

        // Response::assign('pay_url', quickpay_config::$front_pay_url);
        // Response::assign('param', explode('&', $param_string));

        // Response::display(MODULE_PATH.'/openapi/template/pay_form.html');

        Response::redirect(quickpay_config::$front_pay_url.'?'.$param_string);
    }

    /**
     * 退款
     */
    public function refund()
    {
        $refund_id = Request::getParam('refund_id', 0);
        if (!$refund_id) {
            exit('请选择需要退款的订单');
        }

        $refund_info = _uri('refund', $refund_id);
        if (!$refund_info || empty($refund_info)) {
            exit('请选择需要退款的订单');
        }
        _model('refund')->update(array('id'=>$refund_id), array('refund_pay_status'=>1));

        $order_info = _uri('order', $refund_info['order_id']);

        $refund_param = array(
                'transType'     => quickpay_config::REFUND,        // 退款
                'origQid'       => $order_info['transaction_id'],  // 原交易返回的qid, 从数据库中获取
                'orderAmount'   => $refund_info['refund_price']*100,   // 交易金额
                'orderNumber'   => order_helper::order_id_encode($refund_id, 2),       // 订单号，必须唯一(不能与原交易相同)
                'orderTime'     => date('YmdHis', strtotime($order_info['pay_time'])),      // 交易时间, YYYYmmhhddHHMMSS
                'orderCurrency' => quickpay_config::CURRENCY_CNY,  // 交易币种，
                'customerIp'    => get_ip(),                       // 用户IP
                'frontEndUrl'   => '',                             // 前台回调URL, 后台交易可为空
                'backEndUrl'    => AnUrl('openapi/quickpay/refund_notify')    // 后台回调URL
            );

        $refund_param  = $this->build_request_param_string($refund_param);
        $refund_result = $this->quickpay_curl(quickpay_config::$back_pay_url, $refund_param, array(
                CURLOPT_SSL_VERIFYPEER  => quickpay_config::VERIFY_HTTPS_CERT,
                CURLOPT_SSL_VERIFYHOST  => quickpay_config::VERIFY_HTTPS_CERT
            ));
        $return_param = $this->quickpay_response($refund_result);

        // 退款数据是否发送到银联接口
        if ($return_param['respCode'] != '00') {     //错误处理
            _model('refund')->update(array('id'=>$refund_id), array('refund_pay_status'=>0));
            exit($return_param['respMsg']);
        }

        exit('ok');
    }

    /**
     * 银联支付同步通知
     */
    public function pay_return()
    {
        try {
            $return_param = $this->quickpay_response($_POST);
            if ($return_param['respCode'] != '00') {
                throw new Exception("报文错误，respCode不正确！");
            }
            $arr_ret = $return_param;

            //告诉用户交易完成
            $info['id']         = order_helper::order_id_decode($arr_ret['orderNumber']);
            $order_info         = _uri('order', $info['id']);
            if ($order_info['progress'] == 10) {
                return array('交易成功，等待商家发货！', 'error', AnUrl('order'));
            } else {
                return array('交易处理中，请耐心等待', 'error', AnUrl('order'));
            }
            /*
            if ($arr_ret['transType'] == quickpay_config::CONSUME && $order_info['status'] == 1) {
                // 支付订单处理
                $curr_info['progress'] = 10;
                $curr_info['transaction_id'] = $arr_ret['qid'];
                $curr_info['pay_time'] = date('Y-m-d H:i:s', time());
                _model('order')->update(array('id'=>$order_info['id'], 'progress'=>1), $curr_info);

                log_helper::create_pay_log('quickpay', array(
                    'transaction_id' => $arr_ret['qid'],
                    'order_id'       => $info['id'],
                    'total_price'    => $arr_ret['orderAmount']/100,
                    'trade_status'   => 'success',
                    'remarks'        => '支付成功，当前通知为同步通知'
                ));
            }
            return array('付款成功！', 'error', AnUrl('order'));
            */
        } catch(Exception $exp) {
            log_helper::create_pay_log('quickpay', array(
                'transaction_id' => '',
                'order_id'       => '',
                'total_price'    => '',
                'trade_status'   => 'error',
                'remarks'        => '银联支付出现错误：'.$exp->getMessage()
            ));

            return array($exp->getMessage(), 'error', AnUrl('order'));
        }
    }

    public function refund_notify()
    {
        try {
            $return_param = $this->quickpay_response($_POST);
            if ($return_param['respCode'] != '00') {
                throw new Exception("报文错误，respCode不正确！");
            }
            $arr_ret = $return_param;

            if ($arr_ret['transType'] != quickpay_config::REFUND) {
                throw new Exception("当前为重复交易");
            }

            $refund_id = order_helper::order_id_decode($arr_ret['orderNumber']);
            $refund_info = _uri('refund', $refund_id);
            $order_info  = _uri('order', $refund_info['order_id']);

            // 支付订单处理
            $curr_info['refund_status'] = 25;
            $curr_info['refund_pay_status'] = 2;
            $curr_info['transaction_id']  = $arr_ret['qid'];
            _model('refund')->update(array('id'=>$refund_id, 'refund_status'=>20), $curr_info);

            // 发送退款完成短信
            $email = _uri('user', $order_info['user_id'], 'email');
            order_helper::sendExpressMessage('refund_success', array(order_helper::order_id_encode($order_info['id'])), $order_info['mobile'], $email);
                        
            log_helper::create_refund_log('quickpay', array(
                'transaction_id' => $order_info['transaction_id'],
                'order_id'       => $order_info['id'],
                'refund_id'      => $refund_id,
                'transaction_refund_id' => $arr_ret['qid'],
                'refund_fee'     => $refund_info['price'],
                'refund_status'  => 'success',
                'ret_msg'        => '银联退款成功,此通知为异步通知'
            ));
        } catch(Exception $exp) {
            // 后台通知出错
            log_helper::create_refund_log('quickpay', array(
                'transaction_id' => '',
                'order_id'       => '',
                'refund_id'      => '',
                'transaction_refund_id' => '',
                'refund_fee'     => '',
                'refund_status'  => 'error',
                'ret_msg'        => '银联退款失败：'.$exp->getMessage()
            ));

        }
    }

    /**
     * 银联支付异步通知
     */
    public function pay_notify()
    {
        try {
            $return_param = $this->quickpay_response($_POST);
            if ($return_param['respCode'] != '00') {
                throw new Exception("报文错误，respCode不正确！");
            }
            $arr_ret = $return_param;

            //告诉用户交易完成
            $info['id']         = order_helper::order_id_decode($arr_ret['orderNumber']);
            $order_info         = _uri('order', $info['id']);
            if ($arr_ret['transType'] == quickpay_config::CONSUME && $order_info['status'] == 1) {
                // 支付订单处理
                $curr_info['progress'] = 10;
                $curr_info['transaction_id']   = $arr_ret['qid'];
                $curr_info['pay_time'] = date('Y-m-d H:i:s', time());
                _model('order')->update(array('id'=>$order_info['id'], 'progress'=>1), $curr_info);

                log_helper::create_pay_log('quickpay', array(
                    'transaction_id' => $arr_ret['qid'],
                    'order_id'       => $info['id'],
                    'total_price'    => $arr_ret['orderAmount']/100,
                    'trade_status'   => 'success',
                    'remarks'        => '支付成功，当前通知为异步通知'
                ));
            }
        } catch(Exception $exp) {
            // 后台通知出错
            log_helper::create_pay_log('quickpay', array(
                'transaction_id' => '',
                'order_id'       => '',
                'total_price'    => '',
                'trade_status'   => 'error',
                'remarks'        => '银联支付出现错误：'.$exp->getMessage().'.异步通知'
            ));

        }
    }

    private function check_price($price)
    {
        if (is_float($price)) {
            $price = round($price, 2);
        }

        $new_price = $price*100;

        return $new_price;
    }

    /**
     * 生成要请求给银联的参数数组
     * @param $para_temp 请求前的参数数组
     * @return 要请求的参数数组字符串
     */
    private function build_request_param_string($param_temp) {
        $param_temp = array_merge(quickpay_config::$pay_params_empty, $this->quick_config, $param_temp);

        // 从定义merReserved字段
        $new_param  = $this->reset_mer_reserved($param_temp);

        $request_data = '';
        if ($this->check_param($new_param)) {
            //待请求参数数组
            $param_filter = openapi_helper::param_filter($new_param, 1);

            //对待签名参数数组排序
            $param_sort = openapi_helper::param_sort($param_filter);

            //生成签名结果
            $mysign = openapi_helper::build_request_sign($param_sort, quickpay_config::$security_key, 'quickpay');

            //签名结果与签名方式加入请求提交参数组中
            $param_sort['signature']  = $mysign;
            $param_sort['signMethod'] = quickpay_config::$sign_method;

            //把参数组中所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串，并对字符串做urlencode编码
            $request_data = http_build_query($param_sort); 
        }

        return $request_data;
    }

    /**
     * merReserved 重新定义
     */
    private function reset_mer_reserved($param_temp)
    {
        //merReserved: 前后台支付、查询
        $has_reserved = false;
        $arr_reserved = array();
        foreach (quickpay_config::$mer_params_reserved as $key) {
            if (isset($param_temp[$key])) {
                $value = $param_temp[$key];
                unset($param_temp[$key]);
                $arr_reserved[] = "$key=$value";
                $has_reserved = true;
            }
        }
        if ($has_reserved) {
            $param_temp['merReserved'] = sprintf("{%s}", join("&", $arr_reserved));
        } else {
            //请求一定有merReserved字段
            if (!isset($param_temp['merReserved'])) {
                $param_temp['merReserved'] = '';
            }
        }

        return $param_temp;
    }

    /**
     * 验证支付字段
     */
    private function check_param($param)
    {
        $param_check = quickpay_config::$pay_params_check;
        foreach ($param_check as $key) {
            if (!isset($param[$key])) {
                return false;
            }
        }

        return true;
    }

    /*
     * qucikpay_curl
     */
    private function quickpay_curl($url, $data = null, $options = null)
    {
        $curl = curl_init();

        if ($data) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_TIMEOUT, 60); //seconds

        if (is_array($options)) {
            foreach($options as $key => $value) {
                curl_setopt($curl, $key, $value);
            }
        }

        $ret_data = curl_exec($curl);

        if (curl_errno($curl)) {
            printf("curl call error(%s): %s\n", curl_errno($curl), curl_error($curl));
            curl_close($curl);
            return false;
        } else {
            //printf("curl call ok, ret_data: %s\n", $ret_data);
            curl_close($curl);
            return $ret_data;
        }
    }

    /**
     * 请求验证
     */
    private function quickpay_response($param)
    {
        $arr_args = array();
        $arr_reserved = array();
        if (is_array($param)) {  // 如果返回的是数组
            $arr_args       = $param;
            $cupReserved    = isset($arr_args['cupReserved']) ? $arr_args['cupReserved'] : '';
            parse_str(substr($cupReserved, 1, -1), $arr_reserved); //去掉前后的{}
        } else {
            $cupReserved = '';
            $pattern     = '/cupReserved=(\{.*?\})/';
            if (preg_match($pattern, $param, $match)) { //先提取cupReserved
                $cupReserved = $match[1];
            }
            //将cupReserved的value清除(因为含有&, parse_str没法正常处理)
            $args_r         = preg_replace($pattern, 'cupReserved=', $param);
            parse_str($args_r, $arr_args);
            $arr_args['cupReserved'] = $cupReserved;
            parse_str(substr($cupReserved, 1, -1), $arr_reserved); //去掉前后的{}
        }

        //验证签名
        $param_filter = openapi_helper::param_filter($arr_args, 1);
        $param_sort   = openapi_helper::param_sort($param_filter);
        $prestr       = openapi_helper::create_link_string($param_sort);
        if (!openapi_helper::md5_verify($prestr, $arr_args['signature'], quickpay_config::$security_key, 'quickpay')) {
            return array();
        }

        $arr_args = array_merge($arr_args, $arr_reserved);
        unset($arr_args['cupReserved']);

        return $arr_args;
    }
}
?>